plugin_MultiClipboard:
	
	; init for multiple clipboard
	mc_IsOpen := 0
	mc_MaxMemEntry := 7
	mc_PreviewLen := 50
	mc_HistoryFile = data\multi-clipboard.txt
	mc_MagicID := "-=-=--====-=-=-=--"
	Menu, mc_menu, Add
	mc_K1:="7", mc_K2:="8", mc_K3:="9", mc_K4:= "0", mc_K5:="u", mc_K6:="i", mc_K7:="o", mc_K8:="p"
	
	; init for double Ctrl+V
	LastCtrlV := 0
	LastCtrlV_Num := -1
	SetTimer, DoCtrlV, %DoublePressTime%
	SetTimer, DoCtrlV, Off
return

; =================================================
; Multiple (text) clipboard
; -------------------------------------------------
OnClipboardChange:
	if (not__first__call) {
		if (clipboard<>"") {
			mc_AddClipboard()
			ToolTip, Clipboard changed!
			SetTimer, OnClipboardChange_RemoveToolTip, -%DoublePressTime%
		}
	}
	else
		not__first__call := 1
return

OnClipboardChange_RemoveToolTip:
	ToolTip
return

mc_AddClipboard(ByRef text="")
{
	global
	local dup
	
	if (!text)
		text := clipboard
	
	; add to memory entries
	dup := mc_AddMemEntry(text)
	
	; log to disk file
	if (!dup)
		FileAppend, `n%mc_MagicID%%A_YYYY%%A_MM%%A_DD%%mc_MagicID%%text%, %mc_HistoryFile%
}

mc_AddMemEntry(ByRef text)
{
	global
	local entry, dup, movenum, idx, idx2
	
	; find dup
	Loop, %mc_MaxMemEntry%
	{
		entry := mc_Entry%A_Index%
		if (text = entry) {
			dup := A_Index
			break
		}
	}

	; move space for new entry
	movenum := (dup ? dup : mc_MaxMemEntry) - 1
	Loop, %movenum%
	{
		idx := movenum - A_Index + 1
		idx2 := idx + 1
		mc_Entry%idx2% := mc_Entry%idx%
		mc_Title%idx2% := mc_Title%idx%
	}
	
	; add new entry
	mc_Entry1 := text
	mc_Title1 := (StrLen(text) <= mc_PreviewLen) ? text : SubStr(text, 1, mc_PreviewLen) . "..."
	StringReplace, mc_Title1, mc_Title1, `r, %A_Space%, All
	StringReplace, mc_Title1, mc_Title1, `n, %A_Space%, All
	
	return dup
}

mc_OpenMultiClipboard(move=0)
{
	global
	local entry, title, opt, key, options
	Critical
	
	; decide the current entry
	mc_IsOpen := mc_IsOpen + move
	if (!mc_Entry%mc_IsOpen%) {
		mc_IsOpen := mc_IsOpen - move
	}
	if (!mc_Entry%mc_IsOpen%) {
		mc_IsOpen := mc_Entry1 ? 1 : -1
	}
	
	; compose options
	Menu, mc_menu, DeleteAll
	Loop, %mc_MaxMemEntry%
	{
		entry := mc_Entry%A_Index%
		title := mc_Title%A_Index%
		
		if (entry) {
			opt := mc_K%A_Index% . ")`t" . title
			if (mc_IsOpen = A_Index)
				opt := " -> " . opt
			else
				opt := "      " . opt
			if (options)
				options := options . "`n" . opt
			else
				options := opt
			
			; register key
			mc_KNum := A_Index
			key := "^" . mc_K%A_Index%
			Hotkey, %key%, mc_OnKeyOfMultiClipboard, On
		}
	}
	options := options . "`n" . mc_MagicID . mc_MagicID . "`n      n)`tcancel" . "`n      m)`tmore history"
	Hotkey, ^m, mc_OnKeyOfMultiClipboard, On
	Hotkey, ^n, mc_OnKeyOfMultiClipboard, On
	Hotkey, ^Up, mc_OnKeyOfMultiClipboard, On
	Hotkey, ^Down, mc_OnKeyOfMultiClipboard, On
	tooltip, %options%, , , 19
	
	; remember to close
	SetTimer, mc_CheckMultiClipboard, 200
}

mc_CheckMultiClipboard:
	if (!GetKeyState("Control"))
	{
		mc_FinishMultiClipboard()
	}
return

mc_FinishMultiClipboard(choice=0)
{
	global
	local key, entry
	Critical
	
	if (!choice)
		choice := mc_IsOpen
	if (!mc_IsOpen)
		return
	mc_IsOpen := 0
	
	SetTimer, mc_CheckMultiClipboard, Off
	
	; clear options
	tooltip, , , , 19
	
	; unregister keys
	Hotkey, ^m, Off
	Hotkey, ^n, Off
	Hotkey, ^Up, Off
	Hotkey, ^Down, Off
	Loop, %mc_KNum%
	{
		key := "^" . mc_K%A_Index%
		Hotkey, %key%, Off
	}
	
	; paste selection
	if (choice > 0) {
		clipboard := mc_Entry%choice%
		Paste()
	}
}

mc_OnKeyOfMultiClipboard:
	if ("^m" = A_ThisHotkey) {
		Run, %mc_HistoryFile%
		mc_FinishMultiClipboard(-1)
	}
	else if ("^n" = A_ThisHotkey) {
		mc_FinishMultiClipboard(-1)
	}
	else if ("^Up" = A_ThisHotkey) {
		mc_OpenMultiClipboard(-1)
	}
	else if ("^Down" = A_ThisHotkey) {
		mc_OpenMultiClipboard(1)
	}
	else {
		Loop, %mc_MaxMemEntry%
		{
			if ("^" . mc_K%A_Index% = A_ThisHotkey) {
				mc_FinishMultiClipboard(A_Index)
			}
		}
	}
return

; =================================================
; Double Ctrl+V to paste as plain text
; -------------------------------------------------
$^v::
	Critical
	
	; subsequent Ctrl+V
	if (LastCtrlV_Num >= 0) {
		LastCtrlV_Num++
		SetTimer, DoCtrlV, Off ; cancel the first Ctrl+V
		
		; quick double Ctrl+V
		if (LastCtrlV_Num = 1 && A_TickCount-LastCtrlV < DoublePressTime) {
			; kick off multi-clipboard
			mc_OpenMultiClipboard()
		}
		; paste in other case
		else {
			mc_FinishMultiClipboard()
			Paste()
		}
		
		LastCtrlV := 0 ; loose track of quick double Ctrl+V
	}
	; first Ctrl+V
	else {
		LastCtrlV := A_TickCount
		LastCtrlV_Num := 0
		SetTimer, DoCtrlV, On ; delay the first Ctrl+V
	}
return

~Control UP::
	; compensate the first Ctrl+V
	if (LastCtrlV_Num = 0 && LastCtrlV > 0) {
		GoSub, DoCtrlV
	}
	; reset Ctrl+V counter
	LastCtrlV_Num := -1
return

DoCtrlV:
	SetTimer, DoCtrlV, Off
	LastCtrlV := 0 ; indicate the first Ctrl+V is triggered
	Paste()
return

